﻿ /// <reference path="CoordinateConverter/Geo.CoordinateConverter.ts" />

////////////////////////////////////////////////
// Created by Michael Kappel March 12th, 2013 //
// "Core.ts" TypeScript JavaScript            //
// http://www.typescriptlang.org/             //
// Always change Core.ts                      //
// This is the Core Javscript file for        //
// Geotrackable.mobi and should have no       //
// dependencies to any other file or library. //
// This should always be the first file       //
// referenced before any other script.        //
// EXCEPTION:CoordinateConverter              //
////////////////////////////////////////////////


//***********************[ No jQuery in this file ]********************************

//***********************************
// Enumerations                               
//***********************************
module Geo {

    export class String {
        constructor() {

        }
        public static Parse(arg: any): string {
            return arg;
        }
        public static IsNull(arg: string, def: string): string {
            return (arg === undefined || arg === null) ? def : arg;
        }
    }

    export module Enumerations {
        export enum ActionTypes {
            Travel = 0,
            PickUp = 1,
            DropOff = 2
        }
        export enum GeoCacheSiteTypes {
            GeocachingDotCom = 0,
            OpenCachingDotCom = 1,
            OpenCachingDotUs = 2
        }
    }



    //***********************************
    // Interfaces                               
    //http://blogs.msdn.com/b/typescript/archive/2013/01/24/interfaces-walkthrough.aspx
    //***********************************
    export module Interfaces {
        //Data Transfer Objects
        export interface IPrivateKey {
            PrivateKey: string;
        }
        export interface IPublicKey {
            PublicKey: string;
        }
        export interface IHelper {
            queryString(queryStringRaw: string, arg: string): string;
        }
        export interface INavigationController {
            //Step 0
            GoToEntry(): void;

            //Step 1
            GoToAction(arg?: string): void;
            GoToView(arg?: string): void;

            //Step 2
            GoToActionDetail(actionType: Enumerations.ActionTypes, arg?: string): void;

            //Step 3
            GoToUser(actionType: Enumerations.ActionTypes, arg?: string): void;
            GoToLocation(actionType: Enumerations.ActionTypes, arg?: string): void;
            GoToGeocache(actionType: Enumerations.ActionTypes, arg?: string): void;

            //Step 4 EDIT
            GoToActionEdit(lid: number): void;
            GoToUserEdit(lid: number): void;
            GoToLocationEdit(lid: number): void;
            GoToGeocacheEdit(lid: number): void;

        }
        export interface INameValuePair {
            Name: string;
            Value: string;
        }
        export interface INameValuePairs {
            Clear(): void;
            Get(key: string): string;
            Set(key: string, value: string): void;
        }

        export interface INavigationProvider {
            GoTo(url: string, ...params: INameValuePair[]): void;
            GoToMulti(url: string, params: INameValuePair[]): void;
        }

        // Requires reference to CoordinateConverter.ts  for CoordinateConverter.Interfaces.ICoordinateDecimal
        // "export module CoordinateConverter.Interfaces" CoordinateConverter.Interfaces.ICoordinateDecimal
        export interface ICoordinate extends CoordinateConverter.Interfaces.ICoordinateDecimal {

        }
        export interface ILogEntryLid {
            LogEntryLid: number;
        }
        export interface ILogEntry extends ILogEntryLid, IPrivateKey {
            ActionType: Enumerations.ActionTypes;
            UserInteractedWith: string;
            CacheCode: string;
            CacheSiteType: Enumerations.GeoCacheSiteTypes;
            Coordinates: ICoordinate;
        }
        export interface ILogEntryRepository {
            Count(): number;
            Clear(): void;
            Contains(logEntry: Interfaces.ILogEntryLid): bool;
            Add(privateKey: Interfaces.IPrivateKey, actionType: Enumerations.ActionTypes, cacheSiteType: Enumerations.GeoCacheSiteTypes, cacheCode: string, coordinates: Interfaces.ICoordinate, userInteractedWith: string): ILogEntry;
            Remove(logEntry: ILogEntryLid): void;
            Update(logEntry: ILogEntry): void;
            Get(logEntry: ILogEntryLid): ILogEntry;
            GetList(): ILogEntry[];
        }
        export interface IPreloadedData {

        }
        export interface IContext extends ILogEntry {
            IsOnline(): bool;
        }

        export interface IContextInitializer {
            GetCurrentContext(): IContext;
        }

        export interface IEvent {
            add(listener: () => void ): void;
            remove(listener: () => void ): void;
            trigger(...a: any[]): void;
        }

        export interface IEnumLabelProvider {
            GetActionTypeLabel(ActionType: Enumerations.ActionTypes): string;
            GetGeoCacheSiteTypesLabel(GeoCacheSiteType: Enumerations.GeoCacheSiteTypes): string;
        }

        export interface IGeoLocationRepository {
            GetPosition(success: (coordinate: Interfaces.ICoordinate) => void , error: (message: string) => void );
        }

        export interface ILocationProvider {
            OnLocationUpdated: Interfaces.IEvent;
            IsAvailable: bool;
        }
    }

    //***********************************
    // Model                             
    //***********************************
    export module Model {
        export class PrivateKeyInfo implements Interfaces.IPrivateKey {
            private privateKey: string;

            constructor(public privateKey: string) {
                this.privateKey = privateKey;
            }

            get PrivateKey(): string {
                return this.privateKey;
            }
        }
        export class PublicKeyInfo implements Interfaces.IPublicKey {
            private publicKey: string;

            constructor(public publicKey: string) {
                this.publicKey = publicKey;
            }

            get PublicKey(): string {
                return this.publicKey;
            }
        }

        export class ContextInfo implements Interfaces.ILogEntry, Interfaces.IPrivateKey {
            private _isOnlineFunc: () => bool;
            public IsProduction: bool;

            public LogEntryLid: number;
            public PrivateKey: string;
            public ActionType: Enumerations.ActionTypes;
            public UserInteractedWith: string;
            public CacheCode: string;
            public CacheSiteType: Enumerations.GeoCacheSiteTypes;
            public Coordinates: Interfaces.ICoordinate;

            public IsOnline(): bool {
                return this._isOnlineFunc();
            }

            constructor(logEntryLid: number, privateKey: Interfaces.IPrivateKey, actionType: Enumerations.ActionTypes, cacheSiteType: Enumerations.GeoCacheSiteTypes, cacheCode: string, coordinates: Interfaces.ICoordinate, userInteractedWith: string,isOnlineFunc: () => bool, isProduction: bool) {
                //super(logEntryLid, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith);
                this._isOnlineFunc = isOnlineFunc;
                this.IsProduction = isProduction;
                
                this.LogEntryLid = logEntryLid;

                if (privateKey)
                    this.PrivateKey = privateKey.PrivateKey;

                this.ActionType = actionType;
                this.UserInteractedWith = userInteractedWith;
                this.CacheCode = cacheCode;
                this.CacheSiteType = cacheSiteType;
                this.Coordinates = coordinates;
            }
        }

        export class NameValuePairInfo implements Interfaces.INameValuePair {
            public Name: string;
            public Value: string;

            constructor(name: string, value: string) {
                this.Name = name;
                this.Value = value;
            }
        }

        export class LogEntryIdInfo implements Interfaces.ILogEntryLid {
            public LogEntryLid: number;
            constructor(logEntryLid: number) {
                this.LogEntryLid = logEntryLid;
            }
        }

        export class LogEntryInfo extends LogEntryIdInfo implements Interfaces.ILogEntry, Interfaces.IPrivateKey {

            public PrivateKey: string;
            public ActionType: Enumerations.ActionTypes;
            public UserInteractedWith: string;
            public CacheCode: string;
            public CacheSiteType: Enumerations.GeoCacheSiteTypes;
            public Coordinates: Interfaces.ICoordinate;

            constructor(logEntryLid: number, privateKey: Interfaces.IPrivateKey, actionType: Enumerations.ActionTypes, cacheSiteType: Enumerations.GeoCacheSiteTypes, cacheCode: string, coordinates: Interfaces.ICoordinate, userInteractedWith: string) {
                super(logEntryLid);

                this.PrivateKey = privateKey.PrivateKey;
                this.ActionType = actionType;
                this.UserInteractedWith = userInteractedWith;
                this.CacheCode = cacheCode;
                this.CacheSiteType = cacheSiteType;
                this.Coordinates = coordinates;
            }
        }
    }

    //***********************************
    // Core Controller                             
    //***********************************
    export module Controller {
        //"TypedEvent" Strongly typed events in TypeScript 
        //http://typescript.codeplex.com/discussions/402228
        export class TypedEvent implements Interfaces.IEvent {
            // Private member vars
            private _listeners: any[] = [];

            public add(listener: () => void ): void {
                /// <summary>Registers a new listener for the event.</summary>
                /// <param name="listener">The callback function to register.</param>
                this._listeners.push(listener);
            }
            public remove(listener?: () => void ): void {
                /// <summary>Unregisters a listener from the event.</summary>
                /// <param name="listener">The callback function that was registered. If missing then all listeners will be removed.</param>
                if (typeof listener === 'function') {
                    for (var i = 0, l = this._listeners.length; i < l; l++) {
                        if (this._listeners[i] === listener) {
                            this._listeners.splice(i, 1);
                            break;
                        }
                    }
                } else {
                    this._listeners = [];
                }
            }

            public trigger(...a: any[]): void {
                /// <summary>Invokes all of the listeners for this event.</summary>
                /// <param name="args">Optional set of arguments to pass to listners.</param>
                var context = {};
                var listeners = this._listeners.slice(0);
                for (var i = 0, l = listeners.length; i < l; i++) {
                    listeners[i].apply(context, a || []);
                }
            }
        }

        //***********************************
        // Core Helper                             
        //***********************************
        export class Helper implements Interfaces.IHelper {

            constructor() {

            }
            public queryString(queryStringRaw: string, arg: string): string {
                var qsSegment: string[] = queryStringRaw.split("&");
                for (var i = 0; i < qsSegment.length; i++) {
                    var nvp = qsSegment[i].split("=");
                    if (nvp[0] == arg) {
                        return nvp[1];
                    }
                }
            }
        }
        export class SessionNameValuePairs implements Interfaces.INameValuePairs {
            public Clear(): void {
                sessionStorage.clear();
            }
            public Get(key: string): string {
                return sessionStorage[key];
            }
            public Set(key: string, value: string): void {
                sessionStorage[key] = value;
            }
        }
        export class QueryStringNameValuePairs implements Interfaces.INameValuePairs {
            private _items: Interfaces.INameValuePair[] = new Array();

            constructor(queryString: string[]) {
                for (var i = 0; i < queryString.length; i++) {
                    var nvp = queryString[i].split("=");
                    this._items.push(new Model.NameValuePairInfo(nvp[0], nvp[1]));
                }
            }

            public Clear(): void {
                this._items = [];
            }

            public Get(key: string): string {
                for (var i = 0; i < this._items.length; i++) {
                    if (this._items[i].Name == key) {
                        return this._items[i].Value;
                    }
                }
                return null;
            }

            public Set(key: string, value: string): void {
                var wasSet: bool = false;
                for (var i = 0; i < this._items.length; i++) {
                    if (this._items[i].Name == key) {
                        this._items[i].Value = value;
                        wasSet = true;
                    }
                }
                if (!wasSet) {
                    this._items.push(new Model.NameValuePairInfo(key, value));
                }
            }

        }
        export class SessionNavigationProvider implements Interfaces.INavigationProvider {
            private _navigationFunc: (goToUrl: string) => void;
            private _nameValuePairs: Interfaces.INameValuePairs;

            constructor(nameValuePairs: Interfaces.INameValuePairs, navigationFunc: (goToUrl: string) => void ) {
                this._nameValuePairs = nameValuePairs;
                this._navigationFunc = navigationFunc;
            }
            GoTo(url: string, ...pairs: Interfaces.INameValuePair[]): void {
                this.GoToMulti(url, pairs);
            }
            GoToMulti(url: string, pairs: Interfaces.INameValuePair[]): void {
                sessionStorage.clear();
                if (pairs.length > 0) {
                    for (var i = 0; i < pairs.length; i++)
                        this._nameValuePairs.Set(pairs[i].Name, pairs[i].Value);
                }
                this._navigationFunc(url);
            }
        }
        export class QueryStringNavigationProvider implements Interfaces.INavigationProvider {
            private NavigationFunc: (goToUrl: string) => void;
            constructor(navigationFunc: (goToUrl: string) => void ) {
                this.NavigationFunc = navigationFunc;
            }
            GoTo(url: string, ...pairs: Interfaces.INameValuePair[]): void {
                this.GoToMulti(url, pairs);
            }
            GoToMulti(url: string, pairs: Interfaces.INameValuePair[]): void {
                var queryString: string = '';
                if (pairs.length > 0) {
                    queryString = '?';
                    for (var i = 0; i < pairs.length; i++) {
                        if (i > 0) queryString += '&';
                        queryString += pairs[i].Name + '=' + pairs[i].Value;
                    }
                }
                this.NavigationFunc(url + queryString);
            }
        }
        export class GenericNavigationProvider implements Interfaces.INavigationProvider {
            private GetNavigationProviderFunc: () => Interfaces.INavigationProvider;

            constructor(getNavigationProviderFunc: () => Interfaces.INavigationProvider) {
                this.GetNavigationProviderFunc = getNavigationProviderFunc;
            }

            GoTo(url: string, ...pairs: Interfaces.INameValuePair[]): void {
                this.GoToMulti(url, pairs);
            }

            GoToMulti(url: string, pairs: Interfaces.INameValuePair[]): void {
                this.GetNavigationProviderFunc().GoToMulti(url, pairs);
            }
        }
        export class NavigationController implements Interfaces.INavigationController {
            public Code: Interfaces.IPrivateKey;
            private Language: string;
            private NavigationProvider: Interfaces.INavigationProvider;

            constructor(code: Interfaces.IPrivateKey, language: string, navigationProvider: Interfaces.INavigationProvider) {
                this.Code = code;
                this.Language = language;
                this.NavigationProvider = navigationProvider;
            }


            //Step 0
            GoToEntry(): void {
                var url = '/' + this.Language + '/';
                this.NavigationProvider.GoTo(url);
            }

            //Step 1
            GoToAction(arg?: string): void {
                var url: string = '/' + this.Language + '/trackable/Action.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)));
            };

            GoToView(arg?: string): void {
                var url = '/' + this.Language + '/trackable/GoToView.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)));
            }

            //Step 2
            GoToActionDetail(actionType: Enumerations.ActionTypes, arg?: string): void {
                var url = '/' + this.Language + '/trackable/ActionDetail.html';
                this.NavigationProvider.GoTo(url,  new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            }

            //Step 3
            GoToUser(actionType: Enumerations.ActionTypes, arg?: string): void {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            }

            GoToLocation(actionType: Enumerations.ActionTypes, arg?: string): void {
                var url = '/' + this.Language + '/trackable/Location.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            }

            GoToGeocache(actionType: Enumerations.ActionTypes, arg?: string): void {
                var url = '/' + this.Language + '/trackable/Geocache.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            }

            //Step 4 EDIT
            GoToActionEdit(lid: number): void {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            }
            GoToUserEdit(lid: number): void {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            }

            GoToLocationEdit(lid: number): void {
                var url = '/' + this.Language + '/trackable/Location.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            }

            GoToGeocacheEdit(lid: number): void {
                var url = '/' + this.Language + '/trackable/Geocache.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            }


        }
        export class EnglishLabelProvider implements Interfaces.IEnumLabelProvider {
            private actionTypesLabels: string[] = ['Moved', 'Picked Up', 'Dropped Off'];
            private geoCacheSiteTypesLabels: string[] = ['Geocaching.com', ' OpenCaching.com', 'OpenCaching.us'];

            public GetActionTypeLabel(actionType: Enumerations.ActionTypes): string {
                if (actionType == undefined)
                    return null;

                return this.actionTypesLabels[actionType];
            }
            public GetGeoCacheSiteTypesLabel(geoCacheSiteType: Enumerations.GeoCacheSiteTypes): string {
                if (geoCacheSiteType == undefined)
                    return null;

                return this.geoCacheSiteTypesLabels[geoCacheSiteType];
            }
        }
        export class LocationProvider implements Interfaces.ILocationProvider {
            private _locationRepository: Interfaces.IGeoLocationRepository;
            private _onLocationUpdated: Interfaces.IEvent;
            private _isAvailable: bool;
            constructor(onBeforeInitialize: Interfaces.IEvent, locationRepository: Interfaces.IGeoLocationRepository, isAvailable: bool) {
                this._onLocationUpdated = onBeforeInitialize;
                this._locationRepository = locationRepository;
                this._isAvailable = isAvailable;
                locationRepository.GetPosition(this.CurrentPositionResult, this.CurrentPositionError);
            }
            private CurrentPositionResult(result: Interfaces.ICoordinate): void {
                alert(result.Latitude + ' ' + result.Longitude);
            }
            private CurrentPositionError(error: string): void {
                alert(error);
            }
            public get OnLocationUpdated(): Interfaces.IEvent {
                return this._onLocationUpdated;
            }
            public get IsAvailable(): bool {
                return this._isAvailable;
            }
        }
    }

    //***********************************
    // Geo Repositories                             
    //***********************************
    export module Repositories {
        export class LocalStorageLogEntryRepository implements Interfaces.ILogEntryRepository {
            private KeyLogEntries: string = 'LogEntries';
            private KeyLastLogEntryLId: string = 'LastLogEntryLId';
            constructor() {

            }
            Count(): number {
                var logEntries: Interfaces.ILogEntry[] = this.GetList();
                if (!logEntries) return 0;
                return logEntries.length;
            }
            Clear(): void {
                window.localStorage.setItem(this.KeyLogEntries, null);
            }
            Contains(logEntry: Interfaces.ILogEntryLid): bool {
                var logEntries: Interfaces.ILogEntry[] = this.GetList()
                if (!logEntries) return false;
                for (var logIndex in logEntries)
                    if (logEntries[logIndex].LogEntryLid === logEntry.LogEntryLid)
                        return true;
                return false;
            }
            Add(privateKey: Interfaces.IPrivateKey, actionType: Enumerations.ActionTypes, cacheSiteType: Enumerations.GeoCacheSiteTypes, cacheCode: string, coordinates: Interfaces.ICoordinate, userInteractedWith: string): Interfaces.ILogEntry {

                var logEntries: Interfaces.ILogEntry[] = this.GetList()
                if (!logEntries)
                    logEntries = <Interfaces.ILogEntry[]>new Array();

                var lastLogEntryLidRaw: string = window.localStorage.getItem(this.KeyLastLogEntryLId) || "0";
                var logEntryLid: number = parseInt(lastLogEntryLidRaw) + 1;
                window.localStorage.setItem(this.KeyLastLogEntryLId, logEntryLid.toString());
                var result: Interfaces.ILogEntry = new Model.LogEntryInfo(logEntryLid, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith);
                logEntries[(logEntries) ? logEntries.length : 0] = result;
                this.UpdateList(logEntries);
                return result;
            }
            Remove(logEntry: Interfaces.ILogEntryLid): void {
                var logEntriesOriginal: Interfaces.ILogEntry[] = this.GetList();
                var logEntries: Interfaces.ILogEntry[] = <Interfaces.ILogEntry[]>new Array();
                var foundIt: bool = false;
                for (var iRaw in logEntriesOriginal) {
                    var i: number = parseInt(iRaw);
                    if (logEntriesOriginal[i].LogEntryLid === logEntry.LogEntryLid) {
                        foundIt = true;
                    } else {
                        logEntries[(foundIt) ? i - 1 : i] = logEntriesOriginal[i];
                    }
                }
                this.UpdateList(logEntries);
            }

            Update(item: Interfaces.ILogEntry): void {
                var logEntries: Interfaces.ILogEntry[] = this.GetList();
                for (var i in logEntries)
                    if (logEntries[i].LogEntryLid = item.LogEntryLid)
                        logEntries[i] = item;
            }
            UpdateList(logEntries: Interfaces.ILogEntry[]): void {
                var logEntriesRaw: string = JSON.stringify(logEntries);
                window.localStorage.setItem(this.KeyLogEntries, logEntriesRaw);
            }
            Get(logEntry: Interfaces.ILogEntryLid): Interfaces.ILogEntry {
                var logEntries: Interfaces.ILogEntry[] = this.GetList()
                if (!logEntries) return null;
                for (var logIndex in logEntries)
                    if (logEntries[logIndex].LogEntryLid === logEntry.LogEntryLid)
                        return logEntries[logIndex];
                return null;
            }
            GetList(): Interfaces.ILogEntry[] {
                var logEntries: Interfaces.ILogEntry[] = null;
                var logEntriesRaw: string = window.localStorage.getItem(this.KeyLogEntries);

                if (logEntriesRaw == undefined)
                    return null;

                if (logEntriesRaw != null) {
                    logEntries = <Interfaces.ILogEntry[]>JSON.parse(logEntriesRaw);
                }
                return logEntries;
            }
        }
        export class GpsGeoLocationRepository implements Interfaces.IGeoLocationRepository {
            public GetPosition(success: (coordinate: Interfaces.ICoordinate) => void , error: (message: string) => void ) {
                navigator.geolocation.getCurrentPosition((position) => {
                    if (success == undefined) return;
                    success(new Geo.CoordinateConverter.Model.CoordinateDecimalInfo(position.coords.latitude, position.coords.longitude));
                }, (err) => {
                    switch (err.code) {
                        case err.PERMISSION_DENIED:

                            break;
                        case err.POSITION_UNAVAILABLE:

                            break;
                        case err.TIMEOUT:

                            break;
                        default:

                            break;
                    }
                })
            }
        }
    }

    //***********************************
    // Core Configuration                             
    //***********************************
    export class Core {
        // Events
        public static OnBeforeInitialize: Interfaces.IEvent = new Controller.TypedEvent();
        public static OnAfterInitialize: Interfaces.IEvent = new Controller.TypedEvent();

        public static Initialize(isProduction: bool): void {
            this.OnBeforeInitialize.trigger('Core.Initialize|Before');
            this.CoordinateConverter = new Geo.CoordinateConverter.Providers.DecimalAndDmsConverter();
            this.EnumLabelProvider = new Controller.EnglishLabelProvider();
            this.LogEntryRepository = new Repositories.LocalStorageLogEntryRepository();
            this.LocationProvider = new Repositories.GpsGeoLocationRepository();
            
            var queryStringRaw: string = window.location.search.substr(1);
            var queryString: Interfaces.INameValuePairs = new Controller.QueryStringNameValuePairs(queryStringRaw.split("&"));
            var session: Interfaces.INameValuePairs = new Controller.SessionNameValuePairs();

            var isOnlineFunc: () => bool = (): bool => { return window.navigator.onLine; };

            var rawLogEntryLid: string = queryString.Get('e');
            if (rawLogEntryLid) {
                var logEntry: Interfaces.ILogEntry = Geo.Core.LogEntryRepository.Get(new Model.LogEntryIdInfo(parseFloat(rawLogEntryLid)));
                this.Current = new Model.ContextInfo(logEntry.LogEntryLid, logEntry, logEntry.ActionType, logEntry.CacheSiteType, logEntry.CacheCode, logEntry.Coordinates, logEntry.UserInteractedWith, isOnlineFunc, isProduction);
            } else {
                var privateKey: Interfaces.IPrivateKey = null;
                var privateKeyRaw: string = queryString.Get('c');
                if (!privateKeyRaw)
                    privateKeyRaw = session.Get('c');
                if (privateKeyRaw)
                    privateKey = new Model.PrivateKeyInfo(privateKeyRaw)


                var actionType: Enumerations.ActionTypes;
                var actionTypeRaw: string = queryString.Get('at');
                if (!actionTypeRaw)
                    actionTypeRaw = session.Get('at');
                if (actionTypeRaw)
                    actionType = <Enumerations.ActionTypes>parseInt(actionTypeRaw);


                var cacheCode: string = queryString.Get('cc');
                if (!cacheCode)
                    cacheCode = session.Get('cc');

                var cacheSiteType: Enumerations.GeoCacheSiteTypes;
                var cacheSiteTypeRaw: string = queryString.Get('ct');
                if (!actionTypeRaw)
                    actionTypeRaw = session.Get('ct');
                if (actionTypeRaw)
                    actionType = <Enumerations.ActionTypes>parseInt(actionTypeRaw);

                var coordinates: Interfaces.ICoordinate;
                var coordinatesRaw: string = queryString.Get('ll');
                if (!coordinatesRaw)
                    coordinatesRaw = session.Get('ll');
                if (coordinatesRaw)
                    coordinates = this.CoordinateConverter.ParseCoordinateDms(coordinatesRaw).ToCoordinateDecimal();

                var userInteractedWith: string = queryString.Get('ou');
                if (!userInteractedWith)
                    userInteractedWith = session.Get('ou');

                this.Current = new Model.ContextInfo(null, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith, isOnlineFunc, isProduction);
            }
            var navigationProvider: Interfaces.INavigationProvider = new Controller.GenericNavigationProvider(
                function () {
                    var navProvider;

                    if (Geo.Core.Current.IsOnline())
                        navProvider = new Controller.QueryStringNavigationProvider((pathAndQuery: string) => window.location.href = pathAndQuery);
                    else
                        navProvider = new Controller.SessionNavigationProvider(new Controller.SessionNameValuePairs(), (pathAndQuery: string) => window.location.href = pathAndQuery);

                    return navProvider;
                }
            );
            this.Navigation = new Controller.NavigationController(this.Current, 'en', navigationProvider);
            this.OnAfterInitialize.trigger('Core.Initialize|After');
        }
        public static Data: Interfaces.IPreloadedData;
        public static Current: Interfaces.IContext;
        public static CoordinateConverter: Geo.CoordinateConverter.Interfaces.ICoordinateConverter;
        public static Navigation: Interfaces.INavigationController;
        public static LogEntryRepository: Interfaces.ILogEntryRepository;
        public static LocationProvider: Interfaces.IGeoLocationRepository;
        public static EnumLabelProvider: Interfaces.IEnumLabelProvider;
    }
}
